package org.dormi.learn;

import sun.security.pkcs10.PKCS10;
import sun.security.x509.X500Name;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.security.*;
import java.util.Base64;

/**
 * https://www.journaldev.com/223/java-generate-csr-program
 * This class generates PKCS10 certificate signing request
 *
 * @author Pankaj@JournalDev.com
 * @version 1.0
 */
public class GetCSRForUser {
    /** 加密算法 */
    private static final String ALGORITHM_RSA = "RSA";
    private static final int RSA_KEY_LENGTH = 2048;
    private static final String DN_OU = "dce";
    private static final String SIGN_ALGORITHM = "SHA256withRSA";

    // 输入参数, 如 uid-111
    private String uid;

    // 输出
    private String publicKeyPem;
    private String privateKeyPem;
    private String csrPem;

    // 内部变量
    private PublicKey publicKey = null;
    private PrivateKey privateKey = null;
    private KeyPairGenerator keyGen = null;
    private byte[] csr = null;

    public GetCSRForUser(String uid) {
        this.uid = uid;

        try {
            keyGen = KeyPairGenerator.getInstance(ALGORITHM_RSA);
            keyGen.initialize(RSA_KEY_LENGTH, new SecureRandom());
            KeyPair keypair = keyGen.generateKeyPair();
            publicKey = keypair.getPublic();
            privateKey = keypair.getPrivate();
            csr = generatePKCS10(this.uid);

            publicKeyPem = String.format("-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n", Base64.getMimeEncoder().encodeToString(publicKey.getEncoded()));
            privateKeyPem = String.format("-----BEGIN PRIVATE KEY-----\n%s\n-----END PRIVATE KEY-----\n", Base64.getMimeEncoder().encodeToString(privateKey.getEncoded()));
            csrPem = new String(csr);
            csrPem = csrPem.replaceAll(" NEW", "");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private byte[] generatePKCS10(String CN) throws Exception {
        PKCS10 pkcs10 = new PKCS10(publicKey);
        Signature signature = Signature.getInstance(SIGN_ALGORITHM);
        signature.initSign(privateKey);
        X500Name x500Name = new X500Name(CN, DN_OU, "", "", "", "");
        pkcs10.encodeAndSign(x500Name, signature);
        ByteArrayOutputStream bs = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(bs);
        pkcs10.print(ps);
        byte[] c = bs.toByteArray();
        try {
            if (ps != null) ps.close();
            if (bs != null) bs.close();
        } catch (Throwable th) {
            th.printStackTrace();
        }
        return c;
    }

    public String getPublicKeyPem() {
        return this.publicKeyPem;
    }

    public String getPrivateKeyPem() {
        return this.privateKeyPem;
    }

    public String getCsrPem() {
        return this.csrPem;
    }

    public static void main(String[] args) {
        GetCSRForUser userCSR = new GetCSRForUser("uid-999");
        System.out.println(userCSR.getCsrPem());
        System.out.println(userCSR.getPrivateKeyPem());
        System.out.println(userCSR.getPublicKeyPem());
    }
}
